﻿using Microsoft.Extensions.DependencyInjection;
using Modules.Project.Repositories;
using PmSoft;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Modules.Project;

/// <summary>
/// 项目编号主键索引器
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class ProjectNumIndexer
{
    private static readonly ConcurrentDictionary<int, string> idToKeyDict = new();
    private static readonly ConcurrentDictionary<string, int> keyToIdDict = new();
    private static readonly SemaphoreSlim _lock = new(initialCount: 1, maxCount: 1);

    private readonly ProjectInfoRepository projectInfoRepository;

    public ProjectNumIndexer(ProjectInfoRepository projectInfoRepository)
    {
        this.projectInfoRepository = projectInfoRepository;
    }

    /// <summary>
    /// 根据项目ID获取项目编号
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public string GetPrjNum(int id)
    {
        if (idToKeyDict.TryGetValue(id, out string? prjNum))
            return prjNum;

        try
        {
            _lock.Wait();

            if (idToKeyDict.TryGetValue(id, out prjNum))
                return prjNum;

            var projectInfo = projectInfoRepository.Get(id);
            if (projectInfo != null
                && !string.IsNullOrEmpty(projectInfo.PrjNum)
                && idToKeyDict.TryAdd(id, projectInfo.PrjNum))
            {
                return projectInfo.PrjNum;
            }
            return string.Empty;
        }
        finally
        {
            _lock.Release();
        }
    }

    /// <summary>
    /// 根据项目编号获取项目ID
    /// </summary>
    /// <param name="prjNum"></param>
    /// <returns></returns>
    public int? GetId(string prjNum)
    {
        if (keyToIdDict.TryGetValue(prjNum, out int id))
            return id;
        try
        {
            _lock.Wait();

            if (keyToIdDict.TryGetValue(prjNum, out id))
                return id;

            id = projectInfoRepository.GetProjectIdByPrjNum(prjNum);
            if (id > 0 && keyToIdDict.TryAdd(prjNum, id))
                return id;

            return null;
        }
        finally
        {
            _lock.Release();
        }
    }

    public bool Remove(int id)
    {
        if (idToKeyDict.TryRemove(id, out string? key)
            && keyToIdDict.TryRemove(key, out _))
            return true;
        return false;
    }

}
